<?php
#
# dmBridge: a data access framework for CONTENTdm(R)
#
# Copyright © 2009, 2010, 2011 Board of Regents of the Nevada System of Higher
# Education, on behalf of the University of Nevada, Las Vegas
#

/**
 * Abstract base class for class representations of HTML form elements.
 *
 * @author Alex Dolski <alex.dolski@unlv.edu>
 * @license http://www.opensource.org/licenses/mit-license.php
 */
abstract class DMAbstractFormField {

	/** @var array */
	protected $allowed_values = array();
	/** @var array of key-value HTML element attributes */
	protected $attrs = array();
	/** @var DMAbstractForm */
	protected $form;
	/** @var boolean */
	protected $is_enabled = true;
	/** @var boolean */
	protected $is_user_data = false;
	/** @var boolean */
	protected $is_required = true;
	/** @var string */
	protected $label;
	/** @var int */
	protected $max;
	/** @var int */
	protected $maxlength = 0;
	/** @var int */
	protected $min;
	/** @var int */
	protected $minlength = 0;
	/** @var string */
	protected $name;
	/** @var string */
	protected $static_validation_msg;
	/** @var int One of the DMFormField constants */
	protected $type = 1;
	/** @var string */
	protected $validation_msg;
	/** @var string */
	protected $value;


	/**
	 * @param string name
	 * @since 0.4
	 */
	public function __construct($name) {
		$this->setName($name);
	}

	/**
	 * @return array
	 * @since 0.4
	 */
	protected function getAllowedValues() {
		return $this->allowed_values;
	}

	/**
	 * @param v
	 * @since 0.4
	 */
	public function addAllowedValue($v) {
		$this->allowed_values[] = $v;
	}

	/**
	 * @return array of key-value tag attribute pairs
	 * @since 0.4
	 */
	protected function getAttributes() {
		return $this->attrs;
	}

	/**
	 * @param k
	 * @param v
	 * @since 0.4
	 */
	public function addAttribute($k, $v) {
		$this->attrs[$k] = $v;
	}

	/**
	 * @return boolean
	 */
	public function isEnabled() {
		return $this->is_enabled;
	}

	/**
	 * @param bool enabled
	 */
	public function setEnabled($enabled) {
		$this->is_enabled = (bool) $enabled;
	}

	/**
	 * @return DMAbstractForm
	 */
	public function getForm() {
		return $this->form;
	}

	/**
	 * @param DMAbstractForm form
	 */
	public function setForm(DMAbstractForm $form) {
		$this->form = $form;
	}

	/**
	 * @return string
	 * @since 0.4
	 */
	public function getLabel() {
		return $this->label;
	}

	/**
	 * @param string str
	 * @since 0.4
	 */
	public function setLabel($str) {
		$this->label = $str;
	}

	/**
	 * @return string
	 * @since 0.4
	 */
	protected function getHTMLName() {
		$name = sprintf("%s[%s]",
				DMAbstractForm::DATA_PREFIX,
				$this->getName());
		foreach ($this->getForm()->getFields() as $f) {
			if ($f != $this && $f->getName() == $this->getName()
					&& !$f instanceof DMRadioField) {
				$name = sprintf("%s[%s][]",
						DMAbstractForm::DATA_PREFIX,
						$this->getName());
				break;
			}
		}
		return $name;
	}

	/**
	 * @return int
	 * @since 0.4
	 */
	protected function getMax() {
		return $this->max;
	}

	/**
	 * @param int
	 * @since 0.4
	 */
	public function setMax($int) {
		$this->max = (int) $int;
	}

	/**
	 * @return int
	 * @since 0.4
	 */
	protected function getMaxLength() {
		return $this->maxlength;
	}

	/**
	 * @param int
	 * @since 0.4
	 */
	public function setMaxLength($int) {
		$this->maxlength = (int) $int;
	}

	/**
	 * @return int
	 * @since 0.4
	 */
	protected function getMin() {
		return $this->min;
	}

	/**
	 * @param int
	 * @since 0.4
	 */
	public function setMin($int) {
		$this->min = (int) $int;
	}

	/**
	 * @return int
	 * @since 0.4
	 */
	protected function getMinLength() {
		return $this->minlength;
	}

	/**
	 * @param int
	 * @since 0.4
	 */
	public function setMinLength($int) {
		$this->minlength = (int) $int;
	}

	/**
	 * @return string
	 * @since 0.4
	 */
	public function getName() {
		return $this->name;
	}

	/**
	 * @param string name
	 * @since 0.4
	 */
	protected function setName($name) {
		$this->name = $name;
	}

	/**
	 * @return Boolean
	 * @since 0.4
	 */
	protected function isRequired() {
		return $this->is_required;
	}

	/**
	 * @param Boolean bool
	 * @since 0.4
	 */
	public function setRequired($bool) {
		$this->is_required = (bool) $bool;
	}

	/**
	 * @return string
	 * @since 0.4
	 */
	protected function getStaticValidationMessage() {
		return $this->static_validation_msg;
	}

	/**
	 * @param string str
	 * @since 0.4
	 */
	public function setStaticValidationMessage($str) {
		$this->static_validation_msg = (string) $str;
	}

	/**
	 * @return int One of the DMFormFieldType constants
	 * @since 0.4
	 */
	protected function getType() {
		return $this->type;
	}

	/**
	 * @param int type DMFormFieldType constant
	 * @since 0.4
	 */
	public function setType($type) {
		$this->type = $type;
	}

	/**
	 * @return Boolean
	 */
	protected function isUserData() {
		return $this->is_user_data;
	}

	/**
	 * @param bool
	 */
	public function setUserData($bool) {
		$this->is_user_data = $bool;
	}

	/**
	 * @return Boolean
	 * @since 0.4
	 */
	public function isValid() {
		$this->validate();
		return strlen($this->getValidationMessage()) ? false : true;
	}

	/**
	 * @return string
	 * @since 0.4
	 */
	public function getValidationMessage() {
		return $this->validation_msg;
	}

	/**
	 * @param string str
	 * @since 0.4
	 */
	private function setValidationMessage($str) {
		$this->validation_msg = $str;
	}

	/**
	 * @return string Field value
	 * @since 0.4
	 */
	public function getValue() {
		return $this->value;
	}

	/**
	 * @param string value
	 * @since 0.4
	 */
	public function setValue($value) {
		if ($value != $this->getValue()) {
			$this->validation_msg = null;
		}
		$this->value = (string) $value;
	}

	protected function validate() {
		$this->validateRequired();
		$this->validateAllowedValues();
		switch ($this->getType()) {
		case DMFormFieldType::EMAIL:
			$this->validateEmail();
			break;
		case DMFormFieldType::INTEGER:
			$this->validateInteger();
			$this->validateRange();
			break;
		case DMFormFieldType::STRING:
			$this->validateLength();
			break;
		case DMFormFieldType::URL:
			$this->validateURL();
			break;
		}

		if ($this->getValidationMessage()
				&& $this->getStaticValidationMessage()) {
			$this->setValidationMessage($this->getStaticValidationMessage());
		}
	}

	private function validateAllowedValues() {
		if (count($this->getAllowedValues()) > 0) {
			if (!in_array($this->getValue(), $this->getAllowedValues())) {
				$this->setValidationMessage(
					DMLocalizedString::getString("FORM_INVALID_VALUE"));
			}
		}
	}

	private function validateEmail() {
		if (strlen($this->getValue())) {
			if (!DMMailer::isValidEmail($this->getValue())) {
				$this->setValidationMessage(
						DMLocalizedString::getString("FORM_INVALID_EMAIL"));
			}
		}
	}

	private function validateInteger() {
		if ($this->getValue() <> round($this->getValue())) {
			$this->setValidationMessage(
					DMLocalizedString::getString("FORM_NON_INTEGER"));
		}
	}

	private function validateLength() {
		if (strlen($this->getValue()) < $this->getMinLength()
				&& $this->getMinLength() > 0) {
			$this->setValidationMessage(
				sprintf(
					DMLocalizedString::getString("FORM_MIN_LENGTH"),
					$this->getMinLength()));
		}
		else if (strlen($this->getValue()) > $this->getMaxLength()
				&& $this->getMaxLength() > 0) {
			$this->setValidationMessage(
				sprintf(
					DMLocalizedString::getString("FORM_MAX_LENGTH"),
					$this->getMaxLength()));
		}
	}

	private function validateRange() {
		if ($this->getValue() < $this->getMin()) {
			$this->setValidationMessage(
				sprintf(DMLocalizedString::getString("FORM_MIN"),
						$this->getMin()));
		}
		else if ($this->getMax() > 0 && $this->getValue() > $this->getMax()) {
			$this->setValidationMessage(
				sprintf(DMLocalizedString::getString("FORM_MAX"),
						$this->getMax()));
		}
	}

	private function validateRequired() {
		if ($this->isRequired() && strlen($this->getValue()) < 1) {
			switch (get_class($this)) {
				default:
					$this->setValidationMessage(
							DMLocalizedString::getString("FORM_REQUIRED"));
					break;
			}
		}
	}

	private function validateURL() {
		if ($this->getValue()) {
			try {
				$url = new DMURI($this->getValue());
			} catch (DMIllegalArgumentException $e) {
				$this->setValidationMessage(
						DMLocalizedString::getString("FORM_INVALID_URL"));
			}
		}
	}

}

